/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { KEYBOARD_KEY } from '@app-cad/common/Constants';
import { wsApi } from '@app-cad/server';
import { Vector3 } from 'three-legacy';

import {
  CadScene,
  CMEVENTS,
  CSCircle,
  CSLine,
  css2dInputLable,
  MathTool,
  SceneGraph,
} from '@amcax/base';
import { eventCenterManager } from '@app-base/common/events/EventCenterManager';
import { ctx2, userEvents } from '@app-cad/module';

type MouseSphereState = 'none' | 'draw';

interface TrackingData {
  circle: CSCircle;
  rline: CSLine;
  rlabel: css2dInputLable;
}

const cmdMouseSphereInit = async (cmdContext) => {
  const cadScene = ctx2.cadScene as CadScene;
  const sceneSetup = ctx2.viewer.sceneSetup;
  const assisGroup = cadScene.assisGroup;
  eventCenterManager.activeEventCenter.setState('drawing');

  // 固定为 XOY 平面
  const planeNormal: Vector3 = new Vector3(0, 0, 1);
  const planeOrigin: Vector3 = new Vector3(0, 0, 0);

  const lineWidth = 1; // 绘制的线宽
  const lineColor = 0x1890f5; // 线条颜色
  let stepStatus: MouseSphereState = 'none';

  const previewLines: TrackingData = {
    circle: null,
    rline: null,
    rlabel: null,
  };

  let startPoint: Vector3; // 起点 = 圆心
  let endPoint: Vector3; // 终点 = 圆上的某点
  let radius = 0;

  // 注册鼠标键盘
  document.addEventListener('keyup', keyupEvent);
  const canvas = ctx2.container;
  canvas.addEventListener('mouseup', onMouseClick);
  userEvents.on(CMEVENTS.MOUSE_SYS_MOVE, onMouseMove);

  // 命令完成或者取消，释放资源
  async function exitCmdMouseSphere() {
    stepStatus = 'none';

    if (cmdContext) {
      cmdContext.store.highlightCmdId = '';
    }
    // ctx2.state = "default";
    eventCenterManager.activeEventCenter.setState('default');

    userEvents.off(CMEVENTS.MOUSE_SYS_MOVE, onMouseMove);
    canvas.removeEventListener('mouseup', onMouseClick);
    document.removeEventListener('keyup', keyupEvent);

    previewLines.circle?.destroy();
    previewLines.rline?.destroy();
    previewLines.rlabel?.destroy();

    assisGroup.clear();
    SceneGraph.emptyGroup(assisGroup);
    ctx2.viewer.requestRender();
  }

  // 命令完成，调用API
  async function drawDoneCallback() {
    await wsApi.createPrimitive(
      'Sphere',
      {
        center: [startPoint.x, startPoint.y, 0],
        radius: radius,
      },
      [
        [startPoint.x, startPoint.y, 0],
        [0, 0, 1],
        [1, 0, 0],
      ],
    );

    setTimeout(exitCmdMouseSphere, 10);
  }

  // 键盘事件：取消 / 参数输入框回车
  function keyupEvent(e) {
    if (e.key == KEYBOARD_KEY.ESC) {
      exitCmdMouseSphere();
      return;
    }
    if (e.key == KEYBOARD_KEY.ENTER) {
      if (stepStatus == 'draw') {
        radius = Math.abs(previewLines.rlabel.getText());
        drawDoneCallback();
      }
      return;
    }
  }

  // 鼠标点击，绘制步骤确定并进入下一个步骤
  function onMouseClick() {
    if (stepStatus == 'none') {
      stepStatus = 'draw';
      return;
    }
    if (stepStatus == 'draw') {
      drawDoneCallback();
      return;
    }
  }

  // 鼠标移动，记录鼠标点并计算需要的值
  function onMouseMove(e) {
    if (stepStatus == 'none') {
      startPoint = sceneSetup.mouseOnPlane(
        e.mouseEvent.layerX,
        e.mouseEvent.layerY,
        planeNormal,
        planeOrigin,
      );
    }
    if (stepStatus == 'draw') {
      endPoint = sceneSetup.mouseOnPlane(
        e.mouseEvent.layerX,
        e.mouseEvent.layerY,
        planeNormal,
        planeOrigin,
      );
      radius = startPoint.clone().sub(endPoint).length();
      showPreview();
    }
  }

  function showPreview() {
    // draw cirle
    if (!previewLines.circle) {
      previewLines.circle = new CSCircle({
        center: startPoint,
        radius: radius,
        csys: MathTool.createCsysFromPlacement([
          [startPoint.x, startPoint.y, 0],
          [0, 0, 1],
          [1, 0, 0],
        ]),
        lineWidth,
        color: lineColor,
      });
      previewLines.circle.addTo(assisGroup);
    } else {
      previewLines.circle.update({ radius: radius });
    }
    // draw radius line
    if (!previewLines.rline) {
      previewLines.rline = new CSLine({
        vertexs: [
          new Vector3(startPoint.x, startPoint.y, 0),
          new Vector3(endPoint.x, endPoint.y, 0),
        ],
        dashed: true,
        color: lineColor,
        lineWidth,
        depthTest: true,
      });
      previewLines.rline.addTo(assisGroup);
    } else {
      previewLines.rline.setVertexs([
        new Vector3(startPoint.x, startPoint.y, 0),
        new Vector3(endPoint.x, endPoint.y, 0),
      ]);
    }
    // draw input label
    if (!previewLines.rlabel) {
      previewLines.rlabel = new css2dInputLable({
        text: radius,
        position: new Vector3(endPoint.x, endPoint.y, 0),
      });
      previewLines.rlabel.focus();
      previewLines.rlabel.addTo(assisGroup);
    } else {
      previewLines.rlabel.update(
        radius,
        new Vector3(endPoint.x, endPoint.y, 0),
      );
    }

    ctx2.viewer.requestRender();
  }
};

export const cmdMouseSphere = {
  id: 'CmdSphere',
  label: 'command.sphere',
  icon: 'CmdMakeSphere',
  invoke: cmdMouseSphereInit,
};
